﻿#include <iostream>
#include <string>
#include <vector>
using namespace std;
/* 对象行为型模式
1.意图
在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。这样以后就可将对象恢复到原先保存的状态。
2.别名
Token
3.适用性
在以下情况使用备忘录模式：
a.必须保存一个对象在某一个时刻的（部分）状态，这样以后需要时它才能恢复到先前的状态
b.如果一个用接口来让其他对象直接得到这些状态，将会暴露对象的实现细节并破坏对象的封装性。
*/
//备忘录类
class Memento
{
public:
	Memento(string name, pair<int, int> pos) :name(name), pos(pos) {}
	string GetName()
	{
		return name;
	}
	pair<int, int> GetPos()
	{
		return pos;
	}
	void Show()
	{
		cout << name << ":(" << pos.first << "," << pos.second << ")" << endl;
	}
private:
	string name;
	pair<int, int> pos;
};
//原生器
class Chess
{
public:
	Chess(string name, pair<int, int> pos) :name(name), pos(pos) {}
	//走一步
	void SetChess(string name, pair<int, int> pos)
	{
		this->name = name;
		this->pos = pos;
	}
	//保存
	Memento* SaveState()
	{
		return new Memento(name, pos);
	}
	//回退
	void Restore(Memento* memento)
	{
		name = memento->GetName();
		pos = memento->GetPos();
	}
private:
	string name;
	pair<int, int> pos;
};
class Caretaker
{
public:
	void AddMemento(Memento* memento)
	{
		//处理一下回退
		if (step < mems.size())
		{
			mems[step] = memento;
		}
		else
		{
			mems.push_back(memento);
		}		
		step++;
	}
	Memento* GetMemento(int index)
	{
		//步数符合条件
		if (index <= mems.size())
		{
			step = index;
		}
		else
		{
			cout << "超出步数范围,回退到上一步:" << endl;
			step--;
		}
		return mems[step];
	}
	void Show()
	{
		for (int i = 0; i < step; i++)
		{
			cout << "第" << i + 1 << "手:";
			mems[i]->Show();
		}
	}
protected:
	vector<Memento*> mems;
	static int step;
};
int Caretaker::step = 0;
/*
int main()
{
	Chess* pc = new Chess("炮", { 3,3 });
	Caretaker* pcaretaker = new Caretaker;
	pcaretaker->AddMemento(pc->SaveState());
	pcaretaker->Show();
	cout << endl;

	pc->SetChess("车", { 4,3 });
	pcaretaker->AddMemento(pc->SaveState());
	pcaretaker->Show();
	cout << endl;

	pc->SetChess("马", { 1,3 });
	pcaretaker->AddMemento(pc->SaveState());
	pcaretaker->Show();
	cout << endl;

	pc->Restore(pcaretaker->GetMemento(4));
	pcaretaker->Show();
	cout << endl;

	pc->SetChess("炮", { 6,6 });
	pcaretaker->AddMemento(pc->SaveState());
	pcaretaker->Show();
	return 0;
}
*/